package edu.ccut.saturn.workflow.parse;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;

import edu.ccut.saturn.component.DefaultComponent;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.workflow.common.Constants;
import edu.ccut.saturn.workflow.common.Dom4jUtils;
import edu.ccut.saturn.workflow.model.ActivityInfo;
import edu.ccut.saturn.workflow.model.AutoInfo;
import edu.ccut.saturn.workflow.model.DataInfo;
import edu.ccut.saturn.workflow.model.DecisionInfo;
import edu.ccut.saturn.workflow.model.EndInfo;
import edu.ccut.saturn.workflow.model.IfInfo;
import edu.ccut.saturn.workflow.model.LogicKeyInfo;
import edu.ccut.saturn.workflow.model.ManInfo;
import edu.ccut.saturn.workflow.model.ParameterInfo;
import edu.ccut.saturn.workflow.model.PropertyInfo;
import edu.ccut.saturn.workflow.model.StartInfo;
import edu.ccut.saturn.workflow.model.StartLimitInfo;
import edu.ccut.saturn.workflow.model.UserInfo;
import edu.ccut.saturn.workflow.model.WorkFlowInfo;
import edu.ccut.saturn.workflow.model.SubInfo;

public class ParseWorkFlow extends DefaultComponent {
	@SuppressWarnings("unchecked")
	protected WorkFlowInfo parseXml(byte[] xml) throws SaturnComponentException {
		WorkFlowInfo workflowInfo = null;
		InputStream in = null;
		try {
			workflowInfo = new WorkFlowInfo();
			in = new ByteArrayInputStream(xml);
			Document document = Dom4jUtils.getDocment(in);
			Element root = document.getRootElement();
			Element informationElement = root
					.element(Constants.WORKFLOW_INFORMATION);
			workflowInfo.setKey(informationElement
					.elementText(Constants.WORKFLOW_KEY));
			workflowInfo.setName(informationElement
					.elementText(Constants.WORKFLOW_NAME));
			workflowInfo.setVersion(informationElement
					.elementText(Constants.WORKFLOW_VERSION));
			workflowInfo.setDescription(informationElement
					.elementText(Constants.WORKFLOW_DESCRIPTION));
			workflowInfo.setAuthor(informationElement
					.elementText(Constants.WORKFLOW_AUTHOR));
			workflowInfo.setX(informationElement
					.attributeValue(Constants.WORKFLOW_X));
			workflowInfo.setY(informationElement
					.attributeValue(Constants.WORKFLOW_Y));
			// 得到活动列表
			workflowInfo.setActivities(getActivities(root
					.elements(Constants.ACTIVITY)));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return workflowInfo;
	}

	private List<ActivityInfo> getActivities(List<Element> elements) {
		List<ActivityInfo> activityInfos = new ArrayList<ActivityInfo>();
		if (elements != null) {
			for (Element activityElement : elements) {
				String type = activityElement
						.attributeValue(Constants.ACTIVITY_TYPE);
				if (Constants.ACTIVITY_TYPE_START.equals(type)) {
					ActivityInfo startInfo = new StartInfo();
					putCommonInfo(startInfo, activityElement);
					putXY(startInfo, activityElement);
					putStartInfo((StartInfo)startInfo,activityElement);
					activityInfos.add(startInfo);
				} else if (Constants.ACTIVITY_TYPE_MAN.equals(type)) {
					ActivityInfo manInfo = new ManInfo();
					putCommonInfo(manInfo, activityElement);
					putXY(manInfo, activityElement);
					putManIndividual((ManInfo)manInfo,activityElement);
					activityInfos.add(manInfo);
				} else if (Constants.ACTIVITY_TYPE_AUTO.equals(type)) {
					ActivityInfo autoInfo = new AutoInfo();
					putCommonInfo(autoInfo, activityElement);
					putXY(autoInfo, activityElement);
					activityInfos.add(autoInfo);
				} else if (Constants.ACTIVITY_TYPE_DECISION.equals(type)) {
					ActivityInfo decisionInfo = new DecisionInfo();
					// putCommonInfo(decisionInfo,activityElement);
					putDecisionInfo((DecisionInfo) decisionInfo,
							activityElement);
					putXY(decisionInfo, activityElement);
					activityInfos.add(decisionInfo);
				} else if (Constants.ACTIVITY_TYPE_END.equals(type)) {
					ActivityInfo endInfo = new EndInfo();
					putEndInfo((EndInfo) endInfo, activityElement);
					putXY(endInfo, activityElement);
					activityInfos.add(endInfo);
				} 
				//TODO 添加子流程
				else if (Constants.ACTIVITY_TYPE_SUB.equals(type)) {
					ActivityInfo subInfo = new SubInfo();
					putCommonInfo((SubInfo) subInfo, activityElement);
					putSubInfo((SubInfo) subInfo, activityElement);
					putXY(subInfo, activityElement);
					activityInfos.add(subInfo);
				}
			}
		}

		return activityInfos;
	}
	
	//TODO 添加子流程
	private void putSubInfo(SubInfo subInfo,Element activityElement){
		subInfo.setSubProcess(activityElement.elementText(Constants.ACTIVITY_SUBPROCESS));
		subInfo.setTransferMode(activityElement.elementText(Constants.ACTIVITY_SUBPROCESS_TRANSFERMODE));
	}
	
	private void putManIndividual(ManInfo manInfo, Element activityElement) {
		// TODO Auto-generated method stub
		manInfo.setAfterRequest(activityElement.elementText(Constants.ACTIVITY_AFTER_REQUEST));
		List<LogicKeyInfo> list = getLogicKey(activityElement.element(Constants.ACTIVITY_CUSTOM_USER_LOGIC));
		if(list.size()>0){
			manInfo.setCustomUserLogic(list.get(0));
		}
		manInfo.setObtainFromActivityRadioButton(activityElement.elementText(Constants.ACTIVITY_OBTAINFROMACTIVITYRADIOBUTTON));
	}

	private void putStartInfo(StartInfo startInfo, Element activityElement) {
		// TODO Auto-generated method stub
		startInfo.setStartLimit(getStartLimit(activityElement.element(Constants.ACTIVITY_STARTLIMIT)));
	}

	private StartLimitInfo getStartLimit(Element element) {
		StartLimitInfo startLimit = new StartLimitInfo();
		startLimit.setId(element.elementText(Constants.ACTIVITY_STARTLIMIT_ID));
		startLimit.setLogicKeyInfo(getLogic(element.element(Constants.ACTIVITY_STARTLIMIT_LOGIC)));
		return startLimit;
	}
    /**
     * 得到启动限制中的logic
     * @param element
     * @return
     */
	@SuppressWarnings("unchecked")
	private LogicKeyInfo getLogic(Element element) {
		// TODO Auto-generated method stub
		LogicKeyInfo logicKeyInfo = new LogicKeyInfo();
			logicKeyInfo.setFullKey(element.elementText(Constants.ACTIVITY_STARTLIMIT_LOGIC_FULLKEY));
			logicKeyInfo.setParamList(getParamList(element.elements(Constants.ACTIVITY_STARTLIMIT_LOGIC_PARAMETER)));
			
		return logicKeyInfo;
	}

	@SuppressWarnings("unchecked")
	private List<ParameterInfo> getParamList(List<Element> elements) {
		ArrayList<ParameterInfo> list = new ArrayList<ParameterInfo>();
		if (elements != null) {
			for(Element paramElement :elements){
				ParameterInfo paramInfo = new ParameterInfo();
				paramInfo.setId(paramElement
						.attributeValue(Constants.ACTIVITY_STARTLIMIT_LOGIC_PARAMETER_ID));
				paramInfo.setKey(paramElement
						.getText());
				list.add(paramInfo);
			}
		}
		return list;
	}

	private void putXY(ActivityInfo info, Element activityElement) {
		info.setX(activityElement.attributeValue(Constants.WORKFLOW_X));
		info.setY(activityElement.attributeValue(Constants.WORKFLOW_Y));
	}

	private void putEndInfo(EndInfo endInfo, Element activityElement) {
		endInfo.setId(activityElement.attributeValue(Constants.ACTIVITY_ID));
		endInfo
				.setNext(activityElement
						.attributeValue(Constants.ACTIVITY_NEXT));
		endInfo
				.setType(activityElement
						.attributeValue(Constants.ACTIVITY_TYPE));
		endInfo.setName(activityElement.elementText(Constants.ACTIVITY_NAME));
		endInfo.setStartPolicy(activityElement
				.elementText(Constants.ACTIVITY_STARTPOLICY));
		endInfo.setPolymeMode(activityElement
				.elementText(Constants.ACTIVITY_POLYMEMODE));
		endInfo.setDescription(activityElement
				.elementText(Constants.ACTIVITY_DESCRIPTION));
		endInfo.setLogicKey(getLogicKey(activityElement
				.element(Constants.ACTIVITY_LOGICKEY)));
	}

	private void putDecisionInfo(DecisionInfo decisionInfo,
			Element activityElement) {
		decisionInfo.setId(activityElement
				.attributeValue(Constants.ACTIVITY_ID));
		decisionInfo.setType(activityElement
				.attributeValue(Constants.ACTIVITY_TYPE));
		decisionInfo.setName(activityElement
				.elementText(Constants.ACTIVITY_NAME));
		decisionInfo.setPolymeMode(activityElement
				.elementText(Constants.ACTIVITY_POLYMEMODE));
		decisionInfo.setOffsetMode(activityElement
				.elementText(Constants.ACTIVITY_OFFSETMODE));
		decisionInfo.setDescription(activityElement
				.elementText(Constants.ACTIVITY_DESCRIPTION));
		decisionInfo.setIfinfos(getIfinfo(activityElement));
	}

	@SuppressWarnings("unchecked")
	private List<IfInfo> getIfinfo(Element activityElement) {
		List<IfInfo> ifInfos = new ArrayList<IfInfo>();
		if (activityElement != null) {
			List<Element> ifList = activityElement
					.elements(Constants.ACTIVITY_IF);
			if (ifList != null) {
				for (Element ifElement : ifList) {
					IfInfo ifInfo = new IfInfo();
					ifInfo.setThen(ifElement
							.attributeValue(Constants.ACTIVITY_IF_THEN));
					ifInfo.setExpr(ifElement
							.elementText(Constants.ACTIVITY_IF_EXPR));
					ifInfos.add(ifInfo);
				}
			}
		}
		return ifInfos;
	}

	private void putCommonInfo(ActivityInfo activityInfo,
			Element activityElement) {
		activityInfo.setId(activityElement
				.attributeValue(Constants.ACTIVITY_ID));
		activityInfo.setNext(activityElement
				.attributeValue(Constants.ACTIVITY_NEXT));
		activityInfo.setType(activityElement
				.attributeValue(Constants.ACTIVITY_TYPE));
		activityInfo.setName(activityElement
				.elementText(Constants.ACTIVITY_NAME));
		activityInfo
				.setUrl(activityElement.elementText(Constants.ACTIVITY_URL));
		activityInfo.setStartPolicy(activityElement
				.elementText(Constants.ACTIVITY_STARTPOLICY));
		activityInfo.setTimeLimit(activityElement
				.elementText(Constants.ACTIVITY_TIMELIMIT));
		activityInfo.setPolymeMode(activityElement
				.elementText(Constants.ACTIVITY_POLYMEMODE));
		activityInfo.setOffsetMode(activityElement
				.elementText(Constants.ACTIVITY_OFFSETMODE));
		activityInfo.setValidateUserLogic(activityElement
				.elementText(Constants.ACTIVITY_VALIDATEUSERLOGIC));
		activityInfo.setDescription(activityElement
				.elementText(Constants.ACTIVITY_DESCRIPTION));
		activityInfo.setIsMulWorkItems(activityElement
				.elementText(Constants.ACTIVITY_ISMULWORKITEM));
		//activityInfo.setWorkitemNumStrategy(activityElement
		//		.elementText(Constants.ACTIVITY_WORKITEMNUMSTRATEGY));
		activityInfo.setIsFinishAll(activityElement
				.elementText(Constants.ACTIVITY_ISFINISHALL));
		activityInfo.setFinishRequiredNum(activityElement
				.elementText(Constants.ACTIVITY_FINISHREQUIREDNUM));
		activityInfo.setFinishRequiredPercent(activityElement
				.elementText(Constants.ACTIVITY_FINISHREQUIREDPERCENT));
		activityInfo.setIsAutoCancel(activityElement
				.elementText(Constants.ACTIVITY_ISAUTOCANCEL));
		activityInfo.setLogicKey(getLogicKey(activityElement
				.element(Constants.ACTIVITY_LOGICKEY)));
		activityInfo.setFormData(getFormData(activityElement
				.element(Constants.ACTIVITY_FORMDATA)));
		activityInfo.setUsers(getUsers(activityElement
				.element(Constants.ACTIVITY_USERS)));
		activityInfo.setUserFrom(activityElement
				.elementText(Constants.ACTIVITY_USERFROM));

	}

	@SuppressWarnings("unchecked")
	private List<UserInfo> getUsers(Element usersElement) {
		List<UserInfo> users = new ArrayList<UserInfo>();
		if (usersElement != null) {
			List<Element> userElementList = usersElement
					.elements(Constants.ACTIVITY_USERS_USER);
			if (userElementList != null) {
				for (Element userElement : userElementList) {
					UserInfo user = new UserInfo();
					user.setId(userElement
							.attributeValue(Constants.ACTIVITY_USERS_USER_ID));
					user
							.setName(userElement
									.attributeValue(Constants.ACTIVITY_USERS_USER_NAME));
					user
							.setType(userElement
									.attributeValue(Constants.ACTIVITY_USERS_USER_TYPE));
					users.add(user);
				}
			}
		}
		return users;
	}

	@SuppressWarnings("unchecked")
	private List<DataInfo> getFormData(Element formDataElement) {
		List<DataInfo> datas = new ArrayList<DataInfo>();
		if (formDataElement != null) {
			List<Element> dataElementList = formDataElement
					.elements(Constants.ACTIVITY_FORMDATA_DATA);
			if (dataElementList != null) {
				for (Element dataElement : dataElementList) {
					DataInfo dataInfo = new DataInfo();
					dataInfo
							.setAccessType(dataElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_ACCESSTYPE));
					dataInfo
							.setKey(dataElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_KEY));
					dataInfo
							.setName(dataElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_NAME));
					dataInfo
							.setRequired(dataElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_REQUIRED));
					dataInfo
							.setType(dataElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_TYPE));
					if (Constants.ACTIVITY_FORMDATA_DATA_TYPE_REDIOLIST
							.equals(dataInfo.getType())
							|| Constants.ACTIVITY_FORMDATA_DATA_TYPE_SELECT
									.equals(dataInfo.getType())) {
						dataInfo.setPropertyInfo(getPropertyInfo(dataElement));
					}
					datas.add(dataInfo);
				}
			}
		}
		return datas;
	}

	@SuppressWarnings("unchecked")
	private List<PropertyInfo> getPropertyInfo(Element dataElement) {
		List<PropertyInfo> properties = new ArrayList<PropertyInfo>();
		if (dataElement != null) {
			List<Element> propertyElementList = dataElement
					.elements(Constants.ACTIVITY_FORMDATA_DATA_PROPERTY);
			if (propertyElementList != null) {
				for (Element propertyElement : propertyElementList) {
					PropertyInfo propertyInfo = new PropertyInfo();
					propertyInfo
							.setValue(propertyElement
									.attributeValue(Constants.ACTIVITY_FORMDATA_DATA_PROPERTY_VALUE));
					propertyInfo.setText(propertyElement.getText());
					properties.add(propertyInfo);
				}
			}
		}

		return properties;
	}

	@SuppressWarnings("unchecked")
	private List<LogicKeyInfo> getLogicKey(Element logicKeyElement) {
		List<LogicKeyInfo> keys = new ArrayList<LogicKeyInfo>();
		if (logicKeyElement != null) {
			List<Element> keyElementList = logicKeyElement
					.elements(Constants.ACTIVITY_LOGICKEY_KEY);
			if (keyElementList != null) {
				for (Element keyElement : keyElementList) {
					LogicKeyInfo logicKeyInfo = new LogicKeyInfo();
					logicKeyInfo
							.setFullKey(keyElement
									.attributeValue(Constants.ACTIVITY_LOGICKEY_KEY_FULLKEY));
					logicKeyInfo.setParamList(getLogicParamList(keyElement));
					keys.add(logicKeyInfo);
				}
			}
		}
		return keys;
	}

	@SuppressWarnings("unchecked")
	private List<ParameterInfo> getLogicParamList(Element keyElement) {
		List<ParameterInfo> params = new ArrayList<ParameterInfo>();
		if (keyElement != null) {
			List<Element> paramElementList = keyElement
					.elements(Constants.ACTIVITY_LOGICKEY_PARAMETER);
			if (paramElementList != null) {
				for (Element paramElement : paramElementList) {
					ParameterInfo parameterInfo = new ParameterInfo();
					parameterInfo
							.setId(paramElement
									.attributeValue(Constants.ACTIVITY_LOGICKEY_PARAMETER_ID));
					parameterInfo.setKey(paramElement.getText());
					params.add(parameterInfo);
				}
			}
		}
		return params;
	}

}
